package com.gwd.task.services.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.gwd.task.entity.CodeRepositoryEntity;
import com.gwd.task.exception.DataException;
import com.gwd.task.model.CodeRepositoryDTO;
import com.gwd.task.model.CodeSubmitRecordDTO;
import com.gwd.task.model.CodeSubmitRelateDTO;
import com.gwd.task.model.ProjectModuleDTO;
import com.gwd.task.model.transfer.ProjectGroupInterface;
import com.gwd.task.model.transfer.RepositoryInterface;
import com.gwd.task.repository.CodeRepositoryRepository;
import com.gwd.task.services.*;
import com.gwd.task.untils.ListPredicate;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author zhiyongming
 * @date 2020/12/22 15:19
 */
@Service
public class CodeRepositoryServerImpl implements CodeRepositoryServer {

    @Resource
    private TaskServer taskServer;
    @Resource
    private ProductionEventsServer productionEventsServer;
    @Resource
    private CodeSubmitRecordServer codeSubmitRecordServer;
    @Resource
    private CodeRepositoryRepository codeRepositoryRepository;
    @Resource
    private CodeRepositoryRelateServer codeRepositoryRelateServer;
    @Resource
    private ProjectModuleServer projectModuleServer;
    @Resource
    private TestServer testServer;

    @Override
    public List<CodeRepositoryDTO> find(CodeRepositoryDTO dto) {
        List<CodeRepositoryDTO> list = codeRepositoryRepository.findAll((Specification<CodeRepositoryEntity>)
                (root, query, cb) ->
                        ListPredicate.of(root, query, cb)
                            .equal("type", dto.getType())
                            .equal("status", dto.getStatus())
                .finish().getRestriction()
        ).stream().map(CodeRepositoryDTO::new).collect(Collectors.toList());

        List<ProjectGroupInterface> members = codeRepositoryRepository.findByGroupList();
        List<RepositoryInterface> repList = codeSubmitRecordServer.getRepositoryCount();
        list.stream().peek(c-> {
            members.forEach(m -> {
                if (c.getCrId().equals(m.getCrId())) {
                    c.setMembers(m.getMembers());
                }
            });
            repList.forEach(r -> {
                if (c.getCrId().equals(r.getRepId())) {
                    c.setNum(r.getNum());
                }
            });
        }).forEach(CodeRepositoryDTO::matchNumNull);



        return list;
    }

    @Override
    public List<CodeRepositoryDTO> findAll() {
        return codeRepositoryRepository.findAll().stream().map(CodeRepositoryDTO::new).collect(Collectors.toList());
    }

    @Override
    public void save(CodeRepositoryDTO dto) {
        CodeRepositoryEntity save;
        if (dto.getCrId()!=null) {
            Optional<CodeRepositoryEntity> entity = codeRepositoryRepository.findById(dto.getCrId());
            if (!entity.isPresent()) {
                throw new DataException("crId:" + dto.getCrId() + " 对应的数据不存在.");
            }
            save = entity.get();
        } else {
            save = new CodeRepositoryEntity();
        }
        BeanUtil.copyProperties(dto, save, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(false));
        save.setMembers(Arrays.toString(dto.getProjectIds())
                .replaceAll("\\[","")
                .replaceAll("]","")
                .replaceAll(" ",""));
        Long crId = codeRepositoryRepository.save(save).getCrId();

        codeRepositoryRelateServer.save(crId, Arrays.asList(dto.getProjectIds().clone()));
    }

    @Override
    public void changeStatus(Long crId) {
        codeRepositoryRepository.findById(crId).ifPresent(e -> {
            e.setStatus(e.getStatus()==0?1:0);
            codeRepositoryRepository.save(e);
        });
    }

    @Override
    public List<CodeSubmitRelateDTO> getSubmit(Long crId) {
        /*
         * crId 仓库id
         * 1.按仓库id获取项目列表
         * 2.按项目列表获取每个项目提交详情
         */
        List<CodeSubmitRelateDTO> list =
            codeRepositoryRelateServer.findProjectByCrId(crId);

        // 提交的各种事件详情数据
        List<CodeSubmitRecordDTO> recordDTOList = codeSubmitRecordServer.findByRepository(crId);
        // 模块对应名称
        List<ProjectModuleDTO> moduleDTOList = projectModuleServer.findAll();
        // 循环匹配项目与详情数据，仓库相等和项目相等则把数据插入到children中
        list.stream().peek(c-> {
            recordDTOList.forEach(r -> {
                try {
                    if (c.getCrId().equals(r.getRepId()) && c.getProjectId().equals(r.getProjectId())) {
                        c.addSubmitList(r);
                    }
                    moduleDTOList.forEach(m -> {
                        if (r.getLv1ModuleId().equals(m.getModuleId())) {
                            r.setLv1ModuleName(m.getModuleName());
                        }
                        if (r.getLv2ModuleId().equals(m.getModuleId())) {
                            r.setLv2ModuleName(m.getModuleName());
                        }
                    });
                } catch (NullPointerException ignored) {
                }
            });
        }).forEach(CodeSubmitRelateDTO::computeNum);

        return list;
    }

    @Override
    public void board(Long crId) {
        /*
         * 1.获取该仓库对应的所有待提交的数据
         * 2.处理任务
         * 3.处理生成
         * 4.处理测试
         * 5.跟新待提交数据返回
         */
        List<CodeSubmitRecordDTO> recordDTOList = codeSubmitRecordServer.findByRepository(crId);
        List<Long> taskIds = recordDTOList.stream().filter(d->d.getType()==0).map(CodeSubmitRecordDTO::getRelateId).collect(Collectors.toList());
        List<Long> eventsIds = recordDTOList.stream().filter(d->d.getType()==1).map(CodeSubmitRecordDTO::getRelateId).collect(Collectors.toList());
        List<Long> testIds = recordDTOList.stream().filter(d->d.getType()==2).map(CodeSubmitRecordDTO::getRelateId).collect(Collectors.toList());

        taskServer.board(taskIds);
        productionEventsServer.board(eventsIds);
        testServer.board(taskIds, eventsIds, testIds, crId);

        codeSubmitRecordServer.board(crId);
    }
}
